var __importDefault =
    (this && this.__importDefault) ||
    ((mod) => (mod?.__esModule ? mod : { default: mod }));
Object.defineProperty(exports, "__esModule", { value: true });
exports.ObjectSimplifier = void 0;
const transformation_1 = require("../transformation");
const traverse_1 = __importDefault(require("@babel/traverse"));
const variable_1 = require("../../helpers/variable");
const proxyObject_1 = require("./proxyObject");
const misc_1 = require("../../helpers/misc");
class ObjectSimplifier extends transformation_1.Transformation {
    /**
     * Creates a new transformation.
     * @param ast The AST.
     * @param config The config.
     */
    constructor(ast, config) {
        super(ast, config);
        this.config = config;
    }
    /**
     * Executes the transformation.
     * @param log The log function.
     * @returns Whether any changes were made.
     */
    execute(log) {
        const self = this;
        const usages = [];
        let depth = 0;
        (0, traverse_1.default)(this.ast, {
            enter(path) {
                (0, misc_1.setProperty)(path, "depth", depth++);
                const variable = (0, variable_1.findConstantVariable)(
                    path,
                    proxyObject_1.isProxyObjectExpression,
                );
                if (!variable) {
                    return;
                }
                // check if object values are modified
                for (const referencePath of variable.binding.referencePaths) {
                    if (
                        referencePath.parentPath?.isMemberExpression() &&
                        referencePath.parentPath.parentPath &&
                        referencePath.parentPath.parentPath.isAssignmentExpression() &&
                        referencePath.parentPath.key === "left"
                    ) {
                        if (!self.config.unsafeReplace) {
                            log(
                                `Not replacing object ${variable.name} as it is modified`,
                            );
                            path.skip();
                            return;
                        }
                    }
                }
                const proxyObject = new proxyObject_1.ProxyObject(variable);
                proxyObject.process();
                usages.push(
                    ...proxyObject.getUsages().map((p) => [p, proxyObject]),
                );
            },
        });
        // replace innermost usages first
        usages.sort(
            (a, b) =>
                (0, misc_1.getProperty)(b[0], "depth") -
                (0, misc_1.getProperty)(a[0], "depth"),
        );
        for (const [path, proxyObject] of usages) {
            if (proxyObject.replaceUsage(path)) {
                this.setChanged();
            }
        }
        return this.hasChanged();
    }
}
exports.ObjectSimplifier = ObjectSimplifier;
ObjectSimplifier.properties = {
    key: "objectSimplification",
    rebuildScopeTree: true,
};
